package hydrap2p.speedlimiter;

import java.util.LinkedList;
import java.util.Queue;

import hydrap2p.download.Source;

/**
 * Allows a single download to go at a time, with a certain amount of data per second
 * 
 * @author Walter Huf
 *
 */
public class SingleFIFOQueue implements SpeedLimitedQueue {
	private int amountPerSecond;
	private long lastupdate;
	private final Queue<Transfer> queue;
	
	/**
	 * Initialize the queue with this amount
	 * @param amount
	 */
	public SingleFIFOQueue(int amount)
	{
		queue=new LinkedList<Transfer>();
		lastupdate=-1;
		setSpeed(amount);
	}	
	
	@Override
	public void attempt(Source peer, boolean download, int amount) {
		if (amountPerSecond==0)
			return;
		
		Transfer temp=new Transfer(amount);
		synchronized(queue)
		{
			queue.add(temp);
		}
		temp.start();
		synchronized(queue)
		{
			queue.remove(temp);
		}
	}

	@Override
	public void update() {
		if (amountPerSecond==0)
		{
			clear();
			return;
		}
		if (lastupdate<0)
		{
			lastupdate=System.currentTimeMillis();
		}
		else
		{
			long timediff=System.currentTimeMillis()-lastupdate;
			lastupdate=System.currentTimeMillis();
			if (timediff<0)
				return;
			long longamount=amountPerSecond*timediff/1000+1;
			int amount=(int)Math.min(longamount, Integer.MAX_VALUE);
			while (amount>0 && queue.size()>0)
			{
				synchronized(queue)
				{
					if (queue.size()>0)
						amount-=queue.peek().decrease(amount);
				}
			}
		}
	}

	@Override
	public int size() {
		synchronized(queue)
		{
			return queue.size();
		}
	}

	@Override
	public void clear() {
		while (size()>0)
		{
			synchronized(queue)
			{
				if (queue.size()>0)
					queue.peek().cancel();
			}
		}
	}

	@Override
	public int getSpeed() {
		return amountPerSecond;
	}

	@Override
	public void setSpeed(int amount) {
		amountPerSecond=amount;
		if (amount==0)
			clear();
	}

}
